﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _01.值类型和引用类型
{
    class Program
    {
        static void Main(string[] args)
        {
            {
                Console.WriteLine("Student ---------- Student");
                Student st = new Student()
                {
                    Id = 1,
                    Name = "乔安生"
                };
                Student st1 = st;
                ///true
                Console.WriteLine(object.ReferenceEquals(st1, st));
                st1.Id = 2;
                ///true
                Console.WriteLine(object.ReferenceEquals(st1, st));
                st1.Name = "安生";
                ///true
                Console.WriteLine(object.ReferenceEquals(st1, st));
                st1.Name = "安生1111111111111";
                ///true
                Console.WriteLine(object.ReferenceEquals(st1, st));
                ///上面的必然是 true 因为 new st 的时候，实际上是在 内存中的 栈里面开辟了一块空间然后把引用给了 st 这个变量
                ///创建一个 类型为Student 的 变量叫做 st1 ，然后把 st 赋值给st1因为st中的是一个引用，所以st1里面的也是指向内存中栈里面的那个 Student
                ///所以不管修改 st 还是 st1 他们两个都会改变。
                ///
            }
            {
                Console.WriteLine("Qiao ---------- Qiao");
                Qiao q1 = new Qiao()
                {
                    Id = 1,
                    Name = "乔安生"
                };
                Qiao q2 = q1;
                ///false
                Console.WriteLine(object.ReferenceEquals(q1, q2));
                q2.Id = 2;
                ///false
                Console.WriteLine(object.ReferenceEquals(q1, q2));
                ///true
                Console.WriteLine(object.ReferenceEquals(q1.Name, q2.Name));
                ///Qiao 是一个结构体 创建q1 的时候是在堆里面开辟了一块空间，然后为q1创建自己的值
                ///然后q2 = q1 并不是复制引用，而是在开辟一块空间
                ///所以上面两个都是false，就对了
                ///第三个是true是为什么
                ///虽然Qiao是一个结构是一个值类型，但是值类型中的引用类型，实际的存储地址还是栈里面q1.Name和q2.Name里面放的其实还是一个指向栈的一个地址
            }
            #region 字符串 是 引用类型，但是他比较特殊,CLR对他进行了特殊的处理
            {
                Console.WriteLine("string ---------- string");
                string str1 = "111111111111111111111";
                string str2 = str1;
                ///true
                Console.WriteLine(object.ReferenceEquals(str1, str2));
                str1 = "22";
                ///false
                Console.WriteLine(object.ReferenceEquals(str1, str2));
                ///第一个是没有啥问题的
                ///但是第二个为啥
                ///因为字符串是不可变的，string 每次赋值的时候都是创建一个新的字符串
                ///所以 str1 和 str2 是不一样的。
            }
            {
                Console.WriteLine("string2 ---------- string2");
                string str1 = "乔安生";
                string str2 = "乔安生";
                ///true
                Console.WriteLine(object.ReferenceEquals(str1, str2));
                ///true
                str1 = "111111";
                str2 = "111111";
                Console.WriteLine(object.ReferenceEquals(str1, str2));
                Student stu = new Student()
                {
                    Id = 1,
                    Name = "111111"
                };
                ///true
                Console.WriteLine(object.ReferenceEquals(str1, stu.Name));
                ///CLR为了节省内存所以特意这么做的。
            }
            #endregion

            Console.ReadLine();
        }
    }

    public class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public struct Qiao
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}
